using System;
using System.Text;
using System.Collections.Generic;
using InfoJetSoft.Service.XPath;

//CID 0164 //2008.12.13 //Begin
namespace InfoJetSoft.Service.XPath.Exprs
{
	/// <summary>
	/// Summary description for RelationExpr.
	/// </summary>
    public class RelationalExpr : IExpr
	{
        private List<IExpr> additiveList = null;

		public RelationalExpr()
		{
			//
			// TODO: Add constructor logic here
			//
        }

        public object Evaluate(ExprContext context)
        {
            //CID 0811 //2011.03.01 //Begin
            object leftValue = null;
            for (int i = 0; i < this.additiveList.Count; i++)
            {
                IExpr expr = this.additiveList[i];
                if (expr is OperatorExpr)
                {
                    OperatorExpr oper = (OperatorExpr)expr;
                    i++;
                    IExpr nextExpr = this.additiveList[i];
                    object rightValue = nextExpr.Evaluate(context);
                    if (oper.Operator == Operator.Lesser || oper.Operator == Operator.LesserEqual || oper.Operator == Operator.Greater || oper.Operator == Operator.GreaterEqual)
                    {
                        leftValue = this.Compare(context, leftValue, rightValue, oper.Operator);
                    }
                    else
                    {
                        throw new Exception("Unsupported operator: " + oper.Operator);
                    }
                }
                else
                {
                    if (leftValue == null)
                    {
                        leftValue = expr.Evaluate(context);
                    }
                    else
                    {
                        throw new Exception("Unsupported expr order");
                    }
                }
            }
            return leftValue;
            //CID 0811 //2011.03.01 //End
        }

        //CID 0866 //2011.04.01 //Begin
        public void Visit(IExprVisitor visitor)
        {
            for (int i = 0; i < this.additiveList.Count; i++)
            {
                IExpr expr = this.additiveList[i];
                expr.Visit(visitor);
            }
        }
        //CID 0866 //2011.04.01 //End

        //CID 0811 //2011.03.01 //Begin
        private bool Compare(ExprContext context, object value1, object value2, Operator op)
        {
            if (value1 is INodeList && value2 is INodeList)
            {
                INodeList nodeList1 = (INodeList)value1;
                INodeList nodeList2 = (INodeList)value2;
                if (op == Operator.Lesser)
                {
                    return NumberFunctions.Min(context, nodeList1) < NumberFunctions.Max(context, nodeList2);
                }
                else if (op == Operator.LesserEqual)
                {
                    return NumberFunctions.Min(context, nodeList1) <= NumberFunctions.Max(context, nodeList2);
                }
                else if (op == Operator.Greater)
                {
                    return NumberFunctions.Max(context, nodeList1) > NumberFunctions.Min(context, nodeList2);
                }
                else
                {
                    return NumberFunctions.Max(context, nodeList1) >= NumberFunctions.Min(context, nodeList2);
                }
            }
            else if (value1 is INodeList || value2 is INodeList)
            {
                INodeList nodeList = null;
                object rightValue = null;
                if (value1 is INodeList)
                {
                    nodeList = (INodeList)value1;
                    rightValue = value2;
                }
                else
                {
                    nodeList = (INodeList)value2;
                    rightValue = value1;
                    if (op == Operator.Lesser)
                    {
                        op = Operator.Greater;
                    }
                    else if (op == Operator.LesserEqual)
                    {
                        op = Operator.GreaterEqual;
                    }
                    else if (op == Operator.Greater)
                    {
                        op = Operator.Lesser;
                    }
                    else
                    {
                        op = Operator.LesserEqual;
                    }
                }
                if (rightValue is bool)
                {
                    double number1 = NumberFunctions.number(context, BooleanFunctions.boolean(nodeList));
                    double number2 = NumberFunctions.number(context, (bool)rightValue);
                    if (op == Operator.Lesser)
                    {
                        return number1 < number2;
                    }
                    else if (op == Operator.LesserEqual)
                    {
                        return number1 <= number2;
                    }
                    else if (op == Operator.Greater)
                    {
                        return number1 > number2;
                    }
                    else
                    {
                        return number1 >= number2;
                    }
                }
                else if (rightValue is double || rightValue is string)
                {
                    double rightDoubleValue = NumberFunctions.number(context, rightValue);
                    foreach (object node in nodeList)
                    {
                        string nodeValue = context.Calculator.GetNodeValue(node);
                        double nodeDoubleValue = NumberFunctions.number(context, nodeValue);
                        if (op == Operator.Lesser && nodeDoubleValue < rightDoubleValue)
                        {
                            return true;
                        }
                        else if (op == Operator.LesserEqual && nodeDoubleValue <= rightDoubleValue)
                        {
                            return true;
                        }
                        else if (op == Operator.Greater && nodeDoubleValue > rightDoubleValue)
                        {
                            return true;
                        }
                        else if (op == Operator.GreaterEqual && nodeDoubleValue >= rightDoubleValue)
                        {
                            return true;
                        }
                    }
                    return false;
                }
                else
                {
                    throw new ExprException("Unsupported data type: " + rightValue.GetType());
                }
            }
            else
            {
                double double1 = NumberFunctions.number(context, value1);
                double doulbe2 = NumberFunctions.number(context, value2);
                if (op == Operator.Lesser)
                {
                    return double1 < doulbe2;
                }
                else if (op == Operator.LesserEqual)
                {
                    return double1 <= doulbe2;
                }
                else if (op == Operator.Greater)
                {
                    return double1 > doulbe2;
                }
                else
                {
                    return double1 >= doulbe2;
                }
            }
        }
        //CID 0811 //2011.03.01 //End

        public void Print(StringBuilder buffer)
        {
            foreach (IExpr expr in this.additiveList)
            {
                expr.Print(buffer);
            }
        }

		public static IExpr Parse( ExprParser parser )
		{
			IExpr additiveExpr = AdditiveExpr.Parse( parser );
			if( additiveExpr != null )
			{
                List<IExpr> list = new List<IExpr>();
				list.Add( additiveExpr );

                OperatorExpr relationOperator = OperatorExpr.ParseRelationalOperator(parser);
				while( relationOperator != null )
				{
					list.Add( relationOperator );

                    IExpr nextAdditiveExpr = AdditiveExpr.Parse(parser);
					if( nextAdditiveExpr == null )
					{
						throw new Exception( "Cannot parse " + parser.XPath );
					}
					list.Add( nextAdditiveExpr );
					
					relationOperator = OperatorExpr.ParseRelationalOperator( parser );
				}

                if (list.Count > 1)
                {
                    RelationalExpr relationExpr = new RelationalExpr();
                    relationExpr.additiveList = list;
                    return relationExpr;
                }
                else
                {
                    return additiveExpr;
                }
			}
			return null;
		}
	}
}
//CID 0164 //2008.12.13 //End
